package com.yonyou.pmclouds.basecom.bp.template;

import com.yonyou.pmclouds.basecom.bp.processor.SingleProcessor;
import com.yonyou.pmclouds.basecom.bp.processor.SingleProcessorWithField;
import com.yonyou.pmclouds.basecom.bp.processor.UpdateTsProcessor;
import com.yonyou.pmclouds.basecom.dao.BaseMapper;
import com.yonyou.pmclouds.basecom.entity.Entity;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.exception.ConcurrentOperationException;
import com.yonyou.pmclouds.basecom.exception.DataModifiedException;
import com.yonyou.pmclouds.basecom.lock.AutoReleaseLockUtil;
import com.yonyou.pmclouds.basecom.util.ChangeFlagCheckUtil;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 单个实体的更新模板
 * <br>
 * 必须提供要更新的字段,不包含changeFlag
 *
 * @author mapeif
 */
public class SingleUpdateBpTemplate<T extends Entity> extends SingleOperateBpTemplate<T> {
    private BaseMapper<T> mapper;
    private String[] fields;
    private boolean needOrig;


    public SingleUpdateBpTemplate(BaseMapper<T> mapper, String[] fields) {
        this.mapper = mapper;
        this.fields = fields;
        this.needOrig = true;
        addBeforeProcessor(new UpdateTsProcessor<T>());
    }

    @Override
    protected T getOrigVO(T vo) throws BusinessException {
        Object pk = vo.pkFiledValue();
        if (pk == null) {
            return null;
        }
        // lock
        if (!AutoReleaseLockUtil.addAutoReleaseLock(pk.toString())) {
            throw new ConcurrentOperationException();
        }
        // get&check
        T orig = mapper.getById(vo.pkFiledValue());
        if (!ChangeFlagCheckUtil.isSameFlag(vo, orig)) {
            throw new DataModifiedException();
        }
        return orig;
    }

    @Override
    protected void operateDirect(T vo, T orig) {
        Set<String> fieldSet = new HashSet<>(Arrays.asList(fields));
        for (SingleProcessor<T> proc : beforeProcessor) {
            if (proc instanceof SingleProcessorWithField) {
                fieldSet.addAll(Arrays.asList(((SingleProcessorWithField) proc).getChangedField()));
            }
        }
        mapper.updateFields(vo, fieldSet.toArray(new String[fieldSet.size()]));
    }

    public T update(T vo) throws BusinessException {
        return execute(vo);
    }
}
